//
//
//

#include "common.h"
#include "ThreadManager.h"
#include "Mutex.h"
#include "WorkThread.h"
#include "LogManager.h"

#undef CLASSCATEGORY
#define CLASSCATEGORY "ThreadManager"

Mutex ThreadManager::_instanceMutex;
ThreadManager* ThreadManager::_sInstance;

ThreadManager* ThreadManager::Instance()
{
	_instanceMutex.Lock();
	if(NULL == _sInstance)
		_sInstance = new ThreadManager();
	_instanceMutex.UnLock();
	return _sInstance;
}

void ThreadManager::DestroyInstance()
{
	_instanceMutex.Lock();
	delete _sInstance;
	_sInstance = NULL;
	_instanceMutex.UnLock();
	LOGTRACE("ThreadManager::DestroyInstance()");
}

ThreadManager::ThreadManager(){};
ThreadManager::~ThreadManager(){};

void* ThreadManager::ThreadEntry(void* pArg)
{
	WorkThread* pThread = (WorkThread*)pArg;
	ThreadManager* pMan = ThreadManager::Instance();

	while(true)
	{
		pMan->_jobListMutex.Lock();
		if(pMan->_jobList.size() == 0)
		{
			pMan->_jobListMutex.UnLock();
			if(pMan->_threadSem.TryWait())
			{
				LOGINFO("_jobList.size() is 0, this thread will exit");
				return NULL;
			}
			usleep(ThreadManager::IDLE_THREAD_SLEEP_TIME);
			continue;
		}

		BaseJob* pJob = pMan->_jobList.front();
		pMan->_jobList.pop_front();
		pMan->_jobListMutex.UnLock();

		pThread->SetJob(pJob);
		pThread->Start();
		delete pJob;
	}
}

//
//
// Initialize thread num of ThreadManager
//
//
bool ThreadManager::Initialize(U32 threadNum)
{
	LOGTRACE("ThreadManager::Initialize");
	U32 tmpNum = threadNum;
	if(tmpNum > ThreadManager::MAX_ALLOW_THREAD_NUM)
	{
		tmpNum = ThreadManager::MAX_ALLOW_THREAD_NUM;
	}

	_threadPoolMutex.Lock();
	for(U32 i = 0; i < tmpNum; ++i)
	{
		WorkThread* p = new WorkThread(this);
		_threadList.push_back(p);
	}
	_threadPoolMutex.UnLock();

	return true;
}

//
//
// Join all subthread and wait until they terminated
bool ThreadManager::WaitAll()
{
	_threadPoolMutex.Lock();
	for(std::list<WorkThread*>::iterator it = _threadList.begin();
			it != _threadList.end();
			it++)
	{
		WorkThread* pThread = (WorkThread*)(*it);
		pthread_join(pThread->GetThreadID(), NULL);
	}
	_threadPoolMutex.UnLock();

	return true;
}

bool ThreadManager::WaitAll(U32 seconds)
{
	return true;
}


U32 ThreadManager::AddJob(BaseJob* pJob)
{
	U32 nRet = 0;

	_jobListMutex.Lock();
	_jobList.push_back(pJob);
	nRet = _jobList.size();
	_jobListMutex.UnLock();

	return nRet;
}


void ThreadManager::SignalExit(void)
{
	int nSize = _threadList.size();
	for(int i = 0; i < nSize; ++i)
	{
		_threadSem.Post();
	}
}
